package com.ztgf.upload.service;

import com.alibaba.simpleimage.SimpleImageException;
import com.ztgf.common.enums.FileErrorCode;
import com.ztgf.common.utils.FileCheck;
import com.ztgf.common.utils.WaterMark;
import com.ztgf.upload.models.service.StoragePoolService;
import com.ztgf.upload.models.service.UploadFileService;
import com.ztgf.upload.models.vo.FastDFSExceptionVO;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboService;
import org.csource.common.MyException;
import org.csource.common.NameValuePair;
import org.csource.fastdfs.StorageClient1;
import org.csource.fastdfs.StorageServer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@DubboService(protocol="hessian")
public class UploadFileServiceImpl implements UploadFileService {

    /**
     * 路径分隔符
     */
    public static final String SEPARATOR = "/";

    /**
     * Point
     */
    public static final String POINT = ".";

    /**
     * 文件名称Key
     */
    private static final String FILENAME = "filename";

    /**
     * 文件最大的大小(Kb)
     */
    @Value("${fdfs.max_file_size}")
    private Integer max_file_size;

    /**
     * 文字水印
     */
    @Value("${fdfs.water_mark}")
    private String water_mark;

    @Autowired
    private StoragePoolService storagePoolService;

    @Override
    public String uploadFileWithMultipart(MultipartFile file) throws FastDFSExceptionVO {
        return uploadfile(file, null);
    }

    /**
     * 以附件形式下载文件
     *
     * @param filepath 文件路径
     * @param response
     */
    @Override
    public void downloadFile(String filepath, HttpServletResponse response) throws FastDFSExceptionVO {
        download(filepath, null, null, response);
    }

    /**
     * 下载文件
     *
     * @param filepath 文件路径
     * @param filename 文件名称
     * @param os 输出流
     * @param response HttpServletResponse
     */
    public void download(String filepath, String filename, OutputStream os, HttpServletResponse response) throws FastDFSExceptionVO {
        if(StringUtils.isBlank(filepath)){
            throw new FastDFSExceptionVO(FileErrorCode.FILE_PATH_ISNULL.CODE, FileErrorCode.FILE_PATH_ISNULL.MESSAGE);
        }

        filepath = toLocal(filepath);
        // 文件名
        if (StringUtils.isBlank(filename)) {
            filename = getFilename(filepath);
        }

        String contentType = FileCheck.EXT_MAPS.get(FileCheck.getFilenameSuffix(filename));

        try {
            StorageServer storageServer = null;
            StorageClient1 storageClient = storagePoolService.getStorageClient(storageServer);
            InputStream is = null;

            // 下载
            byte[] fileByte = storageClient.download_file1(filepath);

            if(fileByte == null){
                throw new FastDFSExceptionVO(FileErrorCode.FILE_NOT_EXIST.CODE, FileErrorCode.FILE_NOT_EXIST.MESSAGE);
            }

            if (response != null) {
                os = response.getOutputStream();

                // 设置响应头
                if (StringUtils.isNotBlank(contentType)) {
                    // 文件编码 处理文件名中的 '+'、' ' 特殊字符
                    String encoderName = URLEncoder.encode(filename, "UTF-8").replace("+", "%20").replace("%2B", "+");
                    response.setHeader("Content-Disposition", "attachment;filename=\"" + encoderName + "\"");
                    response.setContentType(contentType + ";charset=UTF-8");
                    response.setHeader("Accept-Ranges", "bytes");
                }
            }

            is = new ByteArrayInputStream(fileByte);
            byte[] buffer = new byte[1024 * 5];
            int len = 0;
            while ((len = is.read(buffer)) > 0) {
                os.write(buffer, 0, len);
            }
            os.flush();
            is.close();
            os.close();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (MyException e) {
            e.printStackTrace();
            throw new FastDFSExceptionVO(FileErrorCode.FILE_DOWNLOAD_FAILED.CODE, FileErrorCode.FILE_DOWNLOAD_FAILED.MESSAGE);
        }
    }

    /**
     * 使用 MultipartFile 上传
     *
     * @param file MultipartFile
     * @param descriptions 文件描述信息
     * @return 文件路径
     * @throws FastDFSExceptionVO file为空则抛出异常
     */
    public String uploadfile(MultipartFile file, Map<String, String> descriptions) throws FastDFSExceptionVO {
        if(file == null || file.isEmpty()){
            throw new FastDFSExceptionVO(FileErrorCode.FILE_ISNULL.CODE, FileErrorCode.FILE_ISNULL.MESSAGE);
        }
        String path = null;

        try {
            path = upload(file.getInputStream(), file.getOriginalFilename(), descriptions);
        } catch (IOException e) {
            e.printStackTrace();
            throw new FastDFSExceptionVO(FileErrorCode.FILE_ISNULL.CODE, FileErrorCode.FILE_ISNULL.MESSAGE);
        }
        return path;
    }

    /**
     * 上传通用方法
     *
     * @param is 文件输入流
     * @param filename 文件名
     * @param descriptions 文件描述信息
     * @return 组名+文件路径，如：group1/M00/00/00/wKgz6lnduTeAMdrcAAEoRmXZPp870.jpeg
     * @throws FastDFSExceptionVO
     */
    public String upload(InputStream is, String filename, Map<String, String> descriptions) throws FastDFSExceptionVO {
        if(is == null){
            throw new FastDFSExceptionVO(FileErrorCode.FILE_ISNULL.CODE, FileErrorCode.FILE_ISNULL.MESSAGE);
        }

        try {
            if(is.available() > (max_file_size * 1000)){
                throw new FastDFSExceptionVO(FileErrorCode.FILE_OUT_SIZE.CODE, FileErrorCode.FILE_OUT_SIZE.MESSAGE);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 路径 \ /转换
        filename = toLocal(filename);

        // 返回路径
        String path = null;
        // 文件描述
        NameValuePair[] nvps = null;
        List<NameValuePair> nvpsList = new ArrayList<>();
        // 文件名后缀
        String suffix = FileCheck.getFilenameSuffix(filename);

        // 文件名
        if (StringUtils.isNotBlank(filename)) {
            nvpsList.add(new NameValuePair(FILENAME, filename));
        }
        // 描述信息
        if (descriptions != null && descriptions.size() > 0) {
            descriptions.forEach((key, value) -> {
                nvpsList.add(new NameValuePair(key, value));
            });
        }
        if (nvpsList.size() > 0) {
            nvps = new NameValuePair[nvpsList.size()];
            nvpsList.toArray(nvps);
        }

        System.out.println(filename+"3333");
        StorageServer storageServer = storagePoolService.getStorageServer(filename);
        StorageClient1 storageClient = storagePoolService.getStorageClient(storageServer);

        try {
            //判断文件是否是图片
            if (!FileCheck.checkImage(filename)) {
                // 读取流
                byte[] fileBuff = new byte[is.available()];
                is.read(fileBuff, 0, fileBuff.length);
                // 上传文件
                path = storageClient.upload_file1(fileBuff, suffix, nvps);
                is.close();
            } else {
                //添加水印，并返回buff图片
                BufferedImage bufferedImage = WaterMark.addWaterMark(is, water_mark);

                // 创建输出流
                ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
                // 写入流
                ImageIO.write(bufferedImage, suffix, byteArrayOutputStream);
                byteArrayOutputStream.flush();
                byte[] fileBuff = byteArrayOutputStream.toByteArray();
                // 上传文件
                path = storageClient.upload_file1(fileBuff, suffix, nvps);
                // 关流
                byteArrayOutputStream.close();
                is.close();
            }

            if(StringUtils.isBlank(path)) {
                throw new FastDFSExceptionVO(FileErrorCode.FILE_UPLOAD_FAILED.CODE, FileErrorCode.FILE_UPLOAD_FAILED.MESSAGE);
            }

            storageServer.close();
        } catch (IOException e) {
            e.printStackTrace();
            throw new FastDFSExceptionVO(FileErrorCode.FILE_UPLOAD_FAILED.CODE, FileErrorCode.FILE_UPLOAD_FAILED.MESSAGE);
        } catch (MyException e) {
            e.printStackTrace();
            throw new FastDFSExceptionVO(FileErrorCode.FILE_UPLOAD_FAILED.CODE, FileErrorCode.FILE_UPLOAD_FAILED.MESSAGE);
        } catch (SimpleImageException e) {
            e.printStackTrace();
        } finally {
            // 关闭流
            if(is != null){
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return path;
    }

    /**
     * 获取FastDFS文件的名称，如：M00/00/00/wKgzgFnkTPyAIAUGAAEoRmXZPp876.jpeg
     *
     * @param fileId 包含组名和文件名，如：group1/M00/00/00/wKgzgFnkTPyAIAUGAAEoRmXZPp876.jpeg
     * @return FastDFS 返回的文件名：M00/00/00/wKgzgFnkTPyAIAUGAAEoRmXZPp876.jpeg
     */
    public String getFilename(String fileId){
        String[] results = new String[2];
        StorageClient1.split_file_id(fileId, results);

        return results[1];
    }

    /**
     * 转换路径中的 '\' 为 '/' <br>
     * 并把文件后缀转为小写
     *
     * @param path 路径
     * @return
     */
    public String toLocal(String path) {
        if (StringUtils.isNotEmpty(path)) {
            path = path.replaceAll("\\\\", SEPARATOR);

            if (path.contains(POINT)) {
                String pre = path.substring(0, path.lastIndexOf(POINT) + 1);
                String suffix = path.substring(path.lastIndexOf(POINT) + 1).toLowerCase();
                path = pre + suffix;
            }
        }
        return path;
    }
}
